内部排序算法的性能分析

[问题描述]

教科书第10章中,介绍了多种排序算法,并从理论角度对各种算法的时间复杂度进行了分析。依据书中的理论知识,设计一个排序算法比较程序,试比较几种内部排序算法的关键字比较次数和移动次数(关键字交换视为3次移动),以得到对各种排序算法执行效率的直观感受。

[基本要求]

(1)以顺序表作为待排序表的存储结构,其中表长(即关键字个数)不小于100,表中数据随机产生,至少用5组不同数据作比较。

(2)至少实现起泡排序(Bubble)、直接插入排序(Insert)、简单选择排序(Select)、快速排序(Quick)、希尔排序(Shell)、堆排序(Heap)几种基本排序算法。

(3)输出比较结果。分别输出采用各种排序算法对每组数据进行排序前的待排序序列和排序后的排序结果序列;分别输出对应5组数据,各类算法比较的结果表

***线性表结构****

 

typedef struct
{
	ElemType *elem;      //存储空间基址
	int length;          //当前长度
	int listsize;   //当前分配的存储空间容量(以sizeof(ElemType)为单位)
}SqList;

 

 

 

 

 

【分析】

分析每个排序算法在那个位置是在进行位置移动,哪些地方在进行数据比较;比如拿最简单冒泡为例:

 

//起泡排序(Bubble) 
void Bubble(SqList &L)
{
	compare=0,move=0;
	int i,j,t;
	for(j=0;j<L.length-1;j++)
		for(i=0;i<L.length-1-j;i++)
		{   compare++;
			if(L.elem[i]>L.elem[i+1])
			{t=L.elem[i];L.elem[i]=L.elem[i+1];L.elem[i+1]=t;move++;}
		}
}

int compare=0,move=0;        记录比较次数和移动次数

其中两个for循环就是在比较知道比较到了if(L.elem[i]>L.elem[i+1])这句,循环一次compare加一知道条件满足就能进行交换,交换一次move加一。就这样把这组数据排序的比较次数和移动次数都记录出来了。

用了一个简单计数法用compare和move分别记录比较次数和移动次数。

其他排序算法大家照教材一一分析。。。。。。。。

 

直接插入排序(Insert)

 

void Insert(SqList &L)
{
	int i,j;
	for(i=2;i<L.length;++i)
	{
		compare++;
		if(L.elem[i]<L.elem[i-1])
		{
			L.elem[0]=L.elem[i];
			L.elem[i]=L.elem[i-1];
			for(j=i-2;L.elem[i]<L.elem[i-1];--j)
			{
				L.elem[j+1]=L.elem[j];
				move++;  
                compare++; 
			}
			L.elem[j+1]=L.elem[0];
            move+=3;
		}
	}
}


简单选择排序(Select)

 

 

 

 

/***简单选择***/
//简单选择排序(Select)
void Select(SqList &L)
{ 
	compare=0,move=0;
	int i=0,j=0,t=0;    
    for(i=1;i<=L.length;i++)//选择第i小的记录,并交换到位  
    {  
        j=SelectMin(L,i);//在 L.elem[i....L.lengh]中选择key最小的记录  
        if(i!=j)//与第i个记录交换  
        {move++; t=L.elem[i];L.elem[i]=L.elem[j];L.elem[j]=t;}//互换  
    }  
}


int SelectMin(SqList &L,int i)//选取最小  
{  
    int j=1,k=1;  
    for(j=i;j<=L.length;j++)  
    {compare++; if(L.elem[j]<=L.elem[i]) k=j;}  
    return k;  
}
/***简单选择结束***/


快速排序(Quick)

 

 

 

 

/*****快速排序****/
//快速排序(Quick)
void Quick(SqList &L,int low,int high)
{
	int pivot=0;  
    if(low<high)//长度大于1  
    {  
        pivot=QsortPartion(L,low,high);//将L.elem[low...high]一分为二  
        Quick(L,low,pivot-1);//对低子表递归排序,pivot是枢轴位置  
        Quick(L,pivot+1,high);//对高子表递归排序  
    } 
}

void QuickSort(SqList &L)//快速排序  
{  
    Quick(L,1,L.length);  
} 
 
int QsortPartion(SqList &L,int low,int high)//快速排序子函数  
{   
	
    int key=0;  
    key=L.elem[low];//枢轴记录关键字  
    move++;  
    while(low<high)//从表的两端交替地向中间扫描  
    {  
        compare+=2;  
        while(low<high&&L.elem[high]>=key) --high;  
        L.elem[low]=L.elem[high];//将比枢轴记录小的记录移动到低端  
        move++;  
        while(low<high&&L.elem[low]<=key) ++low;  
        L.elem[high]=L.elem[low];//将比枢轴记录大的记录移动到高端  
        move++;  
    }  
    L.elem[low]=key;//枢轴记录到位  
    move++;
    return low;//返回枢轴位置	
}    
/****快速排序结束***/


希尔排序(Shell)

 

 

 

 

/****希尔排序****/
//希尔排序(Shell)
void Shell(SqList &L,int dk )//对顺序表L做一趟希尔插入排序 
{  
    int j;  
    for(int i=dk+1;i<=L.length;i++)  
    {  
        compare++;  
        if(L.elem[i]<L.elem[i-dk])//需将L.elem[i]插入到有序增量子表  
        {  
            L.elem[0]=L.elem[i];//暂存在L.elem[0]  
            move++;  
            for( j=i-dk;j>0&&(L.elem[0]<L.elem[j]);j-=dk)  
            {  
                L.elem[j+dk]=L.elem[j];//记录后移,查找插入位置  
                move++;  
                compare++;  
            }  
            L.elem[j+dk]=L.elem[0];//插入  
            move++;  
        }  
    }  
}  
  
void Shellsort(SqList &L,int dlta[],int t)//按增量序列dlta[0...t-1]对顺序表L做希尔排序  
{  
    int k;  
    compare=0,move=0;  
    for(k=0;k<t;k++)  
        Shell(L,dlta[k]);//一趟增量为dlta[k]的插入排序 
}  
/****希尔排序结束****/


堆排序(Heap)

 

 

 

 

void Heap(SqList &L)//堆排序
{
	int i=1,t;  
    compare=0,move=0;    
    for(i=L.length/2;i>0;i--)  
        HeapAdjust(L,i,L.length);  
    for(i=L.length;i>1;i--)  
    {  
        move++;  
        {t=L.elem[1];L.elem[1]=L.elem[i];L.elem[i]=t;}  
        HeapAdjust(L,1,i-1);  
    }
}

void HeapAdjust(SqList &L,int s,int m)//建堆函数  
{  
    int j,rc;  
    rc=L.elem[s];  
    for(j=2*s;j<=m;j*=2)//沿key较小的孩子结点向下筛选  
    {  
        compare+=2;  
        if(j<m&&(L.elem[j]<L.elem[j+1]))  ++j; //j为key较小的记录的下标  
        if(!(rc<L.elem[j])) break;// 堆调整结束  
        L.elem[s]=L.elem[j]; s=j;//较小的孩子结点值换到父结点位置  
        move++;  
    }  
    L.elem[s]=rc;//rc应插入的位置在s处  
    move++;  	
}  
  
/****堆排序结束****/

 

主要排序算法都给出,其他大家自行设计编写。按照顺序表基本操作实现数据输入和输出。

 

主函数:

 

void main()
{

	int i,j;
	int dlta[3]={5,3,1},t=3;//希尔函数增量数组 
	SqList L1;
	printf("-----|---------------比较次数------------------||---------------移动次数------------------|\n");
	printf(" 分组|Bubble|Insert|Select|Quick |Shell | Heap ||Bubble|Insert|Select|Quick |Shell | Heap |\n");
	for(j=0;j<5;j++)
	{	
	InitList_Sq(L1);
	for(i = 1; i <=100; i++) 
	{
			L1.elem[i]=rand()%100;
            ListInsert_Sq(L1,i,L1.elem[i]);
	}
	printf("\n");
    Bubble(L1);
	Insert(L1);
	Select(L1);
	QuickSort(L1);
    Shellsort(L1,dlta,t);
	Heap(L1);
	printf("  %d |  %d  |  %d  |  %d  |  %d  |  %d  |  %d  ||  %d  |  %d  |  %d  |  %d  |  %d  |  %d  |\n",
		j+1,compare1,compare2,compare3,compare4,compare5,compare6,move1,move2,move3,move4,move5,move6);
	}
}

 

 

 

 

 

最后科普随机数表示 

主要函数    rand()

 

(1)  如果你只要产生随机数而不需要设定范围的话,你只要用rand()就可以了:rand()会返回一随机数值, 范围在0至RAND_MAX 间。RAND_MAX定义在stdlib.h, 其值为2147483647。
例如:

#include<stdio.h>
#include<stdlib.h>
void main()
{
       for(int i=0;i<10;i+)
             printf("%d/n",rand());
}

(2)  如果你要随机生成一个在一定范围的数,你可以在宏定义中定义一个random(int number)函数,然后在main()里面直接调用random()函数:

例如:随机生成10个0~100的数:
#include<stdio.h>
#include<stdlib.h>
#define random(x) (rand()%x)

void main()
{
     for(int x=0;x<10;x++)
           printf("%d/n",random(100));
}

结果展示:(格式没调好,出来不美观,窗口宽度有限

 

  • 6
    点赞
  • 51
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
1、已知一个链表中存储了若干名学生的信息,每名学生的信息包括:学号、英语成绩、数学成绩、计算机成绩。 现编写一个函数search(),要求对输入的无序学号进行排序,然后采用折半查找方法查找输入学生学号,并输出该学生各科成绩。 2、设计一个学生类(CStudent),它具有私有数据成员是:学号、姓名、数学、外语和计算机课程的成绩。要求能实现求三门课总成绩和平均成绩,并能设置和显示学生信息 (类声明和成员函数定义分离)。设计一个友元函数,按照成绩从高到低的顺序输出姓名、学号和成绩信息。 3、实现雇员管理,类Employee需存储雇员的姓名。这种信息对于所有雇员(包括Employee的派生类的雇员)是很普遍的。现在假设从雇员类Employee派生出了小时工类HourlyWorker、计件工类PieceWorker、老板类Boss和销售员类CommissionWorker。小时工每周工作40小时,超过40小时部分的报酬是平时的1.5倍;计件工是按生产的工作件数计算报酬的,每件的报酬是固定的,假设他只生成一种类型的工件,因而类PieceWorker的private数据成员是生产的工件数量和每件的报酬;老板每周有固定的薪水;销售员每周有小部分固定的基本工资加上其每周销售额的固定百分比。设计和规划该类体系,并分别产生每个基类及派生类对象,并显示该员工的工资。 4、约瑟夫生死者游戏 每30个旅客同乘一条船,因为严重超载,加上风高浪大,危险万分;因此船长告诉乘客,只有将全船一半的旅客投入海中,其余人才能幸免遇难。无奈,大家只得同意这种办法,并议定30个人围成一圈,由第一个人数起,依次报数,数到第9人,便把他投入大海中,然后再从他的下一个人数起,数到第9人,再将他扔进大海中,如此循环地进行,直到剩下15个乘客为止。问哪些位置是将是被扔下大海的位置。 5、求二叉树上结点的路径 要求在采用链式存储结构存储的二叉树上,以bt指向根结点,p指向任一给定的结点,编程实现求出从根节点到给定结点之间的路径。 6、图的操作 (1)写出将一个无向图的邻接矩阵转换成邻接表的算法 (2)设计一个算法,判断无向图G是否连通。若连通则返回1; 返回0。 7、内部排序算法性能分析 要求:(1)对冒泡排序、直接排序、简单选择排序、快速排序、希尔排序、堆排序算法进行比较; (2)待排序表的表长不小于100,表中数据随机产生,至少用5组不同数据作比较,比较指标有:关键字参加比较次数和关键字的移动次数(关键字交换记为3次移动); (3)输出各种算法的排序结果和比较结果。 8.2、通讯录管理系统 编程实现通讯录管理系统,要求该系统能够完成通讯信息的建立、查询、插入、删除等基本功能。程序运行后至少给出下面7个菜单项的选择并分别实现其功能: 0、 通讯录的建立 1、通讯录信息输出 2、 通讯者结点信息的删除 3、通讯者结点信息的查询 4、 通讯者结点信息的插入 5、通讯录信息更改 6、 退出通讯录管理系统 设计的任务要求,通讯录中每个学生的基本信息应包括姓名、地址、电话等基本信息,采用链表存储结构。(复习c语言结构体和链表知识)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DXnima

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值